home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
PASCAL
/
1372.ZIP
/
PIBCAT.ARC
/
PIBCAT.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-11-07
|
51KB
|
1,175 lines
(*$V-,R-,S-,B-,I-,F+*)
PROGRAM PibCat;
(*----------------------------------------------------------------------*)
(* *)
(* Program: PIBCAT --- Catalog files on a disk. *)
(* *)
(* Author: Philip R. Burns. *)
(* *)
(* Version: 1.5. November 7, 1988. *)
(* *)
(* Usage: *)
(* PIBCAT v /f=filespec /i=indent /m=margin /l /m=margin /n *)
(* /o=filename /p=pagesize /t=timezone /x /2 *)
(* *)
(* v volume (drive letter) to catalog *)
(* (default is current drive) *)
(* If given as ?, this text is displayed. *)
(* /e=filespec DOS file spec to match when listing *)
(* entries in .ARC/.DWC/.LBR/.MD/.ZOO files *)
(* (default is *.* -- list all entries). *)
(* /f=filespec DOS file spec to match when listing files *)
(* (default is *.* -- list all files) *)
(* /i=indent # columns to space for library entries *)
(* (default is 0) *)
(* /l display long file names in .ZOO and .MD *)
(* files (default is to display short file *)
(* names only) *)
(* /m=margin left margin to leave (default is 0) *)
(* /n expand libraries after main catalog *)
(* listing rather than immediately after *)
(* library file name (default is to expand *)
(* immediately following file name). *)
(* /o=filename write catalog listing to file "filename" *)
(* (default is "CATALOG.LIS") *)
(* /p=pagesize paginate listing using "pagesize" lines *)
(* (default is no pagination) *)
(* /t=timezone number of hours local time lags/leads *)
(* Greenwich Mean Time [GMT] (default is 7) *)
(* /x don't list library file contents *)
(* (default is to list contents) *)
(* /2 Opens files without SHARE for DOS v2.x *)
(* compatibility (default is to open files *)
(* with share for DOS v3.1 and above) *)
(* *)
(* Aborting: Hit ^C to abort catalog listing. *)
(* *)
(* Output: *)
(* *)
(* For each selected file, the file name, size in bytes, and time *)
(* and date of creation are displayed. The same information is *)
(* given for members of .ARC, .DWC, .LBR, .MD, and .ZOO files. *)
(* *)
(* Restrictions: *)
(* *)
(* None. I contribute this program and all source code to the *)
(* public domain. *)
(* *)
(* I do ask as a matter of courtesy that you give me credit if *)
(* you use this code in your own applications. *)
(* *)
(* Acknowledgments: *)
(* *)
(* The archive search code is based upon TPARCV.PAS written by *)
(* Michael Quinlan and ARCV.ASM written by Vern Buerg. *)
(* *)
(* The library search code is based upon LU.PAS written by *)
(* Steve Freeman. *)
(* *)
(* Stephen Falatko suggested and coded the enhancement to list *)
(* the contents of .ARC, .LBR files immediately following their *)
(* appearance in the main catalog listing. I've altered the *)
(* display to make it easier to pick those entries which are .ARC *)
(* and .LBR contents. *)
(* *)
(* Dave Seidman provided a mechanism for getting the volume label *)
(* under MS DOS 2.x. *)
(* *)
(* The format for the .ZOO files was taken from the "C" source *)
(* code to ZOO written by Rahul Dhesi. *)
(* *)
(* The format for the .MD files was extracted from the code *)
(* provided by Mike Davenport. *)
(* *)
(* The format for the .DWC files was extracted from the code *)
(* provided by Dean W. Cooper for his DWC program. *)
(* *)
(* Note: *)
(* *)
(* The routines for processing the various library files are all *)
(* extremely similar. I could have merged them into one big *)
(* routine to avoid the duplicate code. However, I felt it was *)
(* a better idea to leave them separate, even with the extensive *)
(* code duplication, so that you could extract the ones you wanted *)
(* without having to wade through stuff unrelated to the library *)
(* format of interest to you. *)
(* *)
(*----------------------------------------------------------------------*)
(* Global declarations *)
(*$I PIBCAT.GLO *)
(* General service subroutines *)
(*$I PIBCATS1.PAS *)
(*$I PIBCATS2.PAS *)
(*----------------------------------------------------------------------*)
(* Display_Help --- Display help screen for PibCat *)
(*----------------------------------------------------------------------*)
PROCEDURE Display_Help;
VAR
Ch: CHAR;
BEGIN (* Display_Help *)
WRITELN;
WRITELN('Program: PIBCAT --- Catalog files on a disk.');
WRITELN('Author: Philip R. Burns.');
WRITELN('Version: 1.5 November 7, 1988.');
WRITELN('Usage: PIBCAT v /f=filespec /i=indent /m=margin /o=filename /p=pagesize /x /n');
WRITELN(' v volume (drive letter) to catalog');
WRITELN(' (default is current drive)');
WRITELN(' If given as ?, this text is displayed.');
WRITELN(' /e=filespec DOS file spec to match when listing');
WRITELN(' entries in .ARC/.DWC/.LBR/.MD/.ZOO files');
WRITELN(' (default is *.* -- list all entries).');
WRITELN(' /f=filespec DOS file spec to match when listing files');
WRITELN(' (default is *.* -- list all files)');
WRITELN(' /i=indent # columns to space for library entries');
WRITELN(' (default is 0)');
WRITELN(' /l display long file names in .ZOO and .MD');
WRITELN(' files (default is to display short file');
WRITELN(' names only)');
WRITELN(' /m=margin left margin to leave (default is 0)');
WRITELN(' /n list contents of libraries at end of each');
WRITELN(' subdirectory (default is list contents');
WRITELN(' following library file name)');
WRITELN(' /o=filename write catalog listing to file "filename"');
WRITELN(' (default is "CATALOG.LIS")');
WRITELN(' ');
WRITE ('Hit a key to continue: ');
READ( Ch );
WHILE( KeyPressed ) DO
READ( Ch );
WRITELN;
WRITELN;
WRITELN(' /p=pagesize paginate listing using "pagesize" lines');
WRITELN(' (default is no pagination)');
WRITELN(' /t=timezone number of hours local time lags/leads Greenwich');
WRITELN(' Mean Time [GMT] (default is 7)');
WRITELN(' /x don''t list library file contents');
WRITELN(' (default is to list contents)');
WRITELN(' /2 Opens files without SHARE for DOS v2.x');
WRITELN(' compatibility (default is to open files');
WRITELN(' with share for DOS v3.1 and above)');
WRITELN;
WRITELN('Aborting: Hit ^C to abort catalog listing.');
WRITELN;
END (* Display_Help *);
(*----------------------------------------------------------------------*)
(* Initialize --- Initialize PibCat program *)
(*----------------------------------------------------------------------*)
FUNCTION Initialize : BOOLEAN;
VAR
S : AnyStr;
S2 : AnyStr;
I : INTEGER;
J : INTEGER;
IErr : INTEGER;
(* STRUCTURED *) CONST
Legit_Drives : SET OF CHAR = ['A'..'Z','?'];
BEGIN (* Initialize *)
(* --- Set defaults --- *)
(* Drive to catalog is current drive *)
GetDir( 0 , S );
Cat_Drive := UpCase( S[1] );
(* Default output file is CATALOG.LIS *)
Output_File_Name := 'CATALOG.LIS';
(* Don't produce paginated listing file *)
Do_Printer_Format := FALSE;
Page_Size := 0;
(* No extra spaces at left margin *)
Left_Margin := 0;
(* No extra indent for libraries *)
Library_Indent := 0;
(* List contents of library files *)
Expand_Libs := TRUE;
(* Expand libraries after main listing *)
Expand_Libs_In := TRUE;
(* No ^C hit yet terminating cataloguing *)
User_Break := FALSE;
(* Catalog all files by default *)
Find_Spec := '*.*';
(* Catalog all library entries by default *)
Entry_Spec := '*.*';
(* We start on first page *)
Page_Number := 1;
(* Lots of lines left on this page *)
Lines_Left := 32767;
(* No files yet *)
File_Count := 0;
Total_Files := 0;
Total_Space := 0;
Total_Entries := 0;
Total_ESpace := 0;
Total_Dirs := 0;
(* No titles yet *)
Volume_Title := '';
Subdir_Title := '';
File_Title := '';
(* Not help mode only *)
Help_Only := FALSE;
(* Only short file names by default *)
Show_Long_File_Names := FALSE;
(* Assume we are using SHARE *)
Use_Share := TRUE;
(* # of seconds local time leads/lags *)
(* Greenwich Mean Time (GMT) *)
GMT_Difference := 8 * 3600;
(* Assume we do daylight savings adjustment *)
Use_Daylight_Savings := TRUE;
(* Grab command line parameters *)
FOR I := 1 TO ParamCount DO
BEGIN
S := UpperCase( ParamStr( I ) );
IF ( S[1] = '/' ) THEN
BEGIN
IF ( S[3] = '=' ) THEN
S2 := COPY( S, 4, LENGTH( S ) - 3 )
ELSE
S2 := '';
CASE UpCase( S[2] ) OF
(* Match entry within libraries *)
'E': BEGIN
IF ( S2 <> '' ) THEN
Entry_Spec := S2;
END;
(* Match this file spec *)
'F': BEGIN
IF ( S2 <> '' ) THEN
Find_Spec := S2;
END;
(* # of space to indent when listing *)
(* contents of libraries *)
'I': BEGIN
VAL( S2, J, IErr );
IF ( IErr = 0 ) THEN
Library_Indent := J;
END;
(* If long file names should be listed *)
'L': Show_Long_File_Names := TRUE;
(* # of space in left margin of output *)
'M': BEGIN
VAL( S2, J, IErr );
IF ( IErr = 0 ) THEN
Left_Margin := J;
END;
(* Expand libraries after all files *)
(* listed in a subdirectory *)
'N': BEGIN
Expand_Libs_In := FALSE;
Expand_Libs := TRUE;
END;
(* Output file name *)
'O': Output_File_Name := S2;
(* Page size for printing *)
'P': BEGIN
VAL( S2, J, IErr );
IF ( IErr = 0 ) THEN
BEGIN
Page_Size := J;
Lines_Left := J;
END;
Do_Printer_Format := ( Page_Size > 0 );
END;
(* Number of hours or minutes local time *)
(* leads/lags Greenwich Mean Time *)
'T': BEGIN
IF ( LENGTH( S2 ) > 0 ) THEN
BEGIN
J := LENGTH( S2 );
IF ( S2[ J ] = 'A' ) THEN
BEGIN
DELETE( S2 , J , 1 );
Use_Daylight_Savings := FALSE;
END;
VAL( S2, J, IErr );
IF ( IErr = 0 ) THEN
GMT_Difference := J;
IF ( ABS ( GMT_Difference ) <= 12 ) THEN
GMT_Difference := GMT_Difference * 3600
ELSE
GMT_Difference := GMT_Difference * 60;
IF ( ABS( GMT_Difference ) > ( 12 * 3600 ) ) THEN
GMT_Difference := 8 * 3600;
END;
END;
(* If library contents should be expanded *)
'X': Expand_Libs := FALSE;
(* If SHARE to be used when opening files *)
'2': Use_Share := FALSE;
ELSE;
END (* CASE *);
END
ELSE
IF ( S[1] IN Legit_Drives ) THEN
Cat_Drive := S[1];
END;
(* If the drive was a "?" then we have *)
(* a help request. Display help info *)
(* and quit. *)
IF ( Cat_Drive = '?' ) THEN
BEGIN
Display_Help;
Initialize := FALSE;
Help_Only := TRUE;
EXIT;
END;
(* Fix up entry spec for comparisons *)
(* later on. If '*.*', then don't *)
(* bother with entry spec checks later. *)
Check_Entry_Spec( Entry_Spec, Entry_Name, Entry_Ext, Use_Entry_Spec );
(* Get string of blanks for left margin *)
Left_Margin_String := DUPL( ' ' , Left_Margin );
(* Get DOS version and set open *)
(* file modes accordingly. *)
IF ( ( Dos_Version >= 31 ) AND Use_Share ) THEN
BEGIN
Read_Open_Mode := 32;
Write_Open_Mode := 34;
END
ELSE
BEGIN
Read_Open_Mode := 0;
Write_Open_Mode := 2;
END;
(* Open output file *)
FileMode := Write_Open_Mode;
ASSIGN( Output_File , Output_File_Name );
SetTextBuf( Output_File , Output_File_Buffer );
REWRITE( Output_File );
FileMode := 2;
(* Continue if we got it *)
IF ( IOResult <> 0 ) THEN
BEGIN
WRITELN;
WRITELN( 'Can''t open output file ', Output_File_Name );
WRITELN;
Initialize := FALSE;
EXIT;
END;
(* Prevent heap allocation death *)
HeapError := @Heap_Error_Handler;
(* See how many file segments we can get *)
Stack_Alloc := PRED( ( MemAvail - 8192 ) DIV SIZEOF( File_Stack_Type ) );
(* If we can't allocate even one segment *)
(* then report error and quit. *)
IF ( Stack_Alloc < 0 ) THEN
BEGIN
WRITELN;
WRITELN( 'Not enough memory to process file directories ' );
WRITELN;
Initialize := FALSE;
EXIT;
END
ELSE
(* Otherwise, allocate the segments *)
FOR I := 0 TO Stack_Alloc DO
NEW( File_Stack[ I ] );
(* Get bracketing Unix dates for *)
(* daylight savings time calcs. *)
Get_Daylight_Savings_Times;
(* Indicate initialization went OK *)
Initialize := TRUE;
END (* Initialize *);
(*----------------------------------------------------------------------*)
(* Display_Volume_Label --- Display volume label of disk *)
(*----------------------------------------------------------------------*)
PROCEDURE Display_Volume_Label;
VAR
Volume_Label : AnyStr;
Vol_Time : LONGINT;
STime : STRING[10];
SDate : STRING[10];
BEGIN (* Display_Volume_Label *)
(* Blank out volume title line *)
Volume_Title := DUPL( ' ' , 80 );
(* Get volume label from DOS *)
Dir_Get_Volume_Label( Cat_Drive, Volume_Label, Vol_Time );
WRITELN( Output_File );
(* If no volume label, don't output it. *)
IF ( Volume_Label = '' ) THEN
BEGIN
Volume_Title := Left_Margin_String +
' Contents of volume on drive ' +
Cat_Drive +
' as of ' +
DateString +
' ' +
TimeOfDayString;
IF Do_Printer_Format THEN
BEGIN
WRITELN( Output_File , FF_Char );
WRITE ( Output_File , Volume_Title );
WRITELN( Output_File , ' Page ', Page_Number );
END
ELSE
WRITELN( Output_File , Volume_Title );
DEC( Lines_Left );
END
ELSE
(* If volume label, output it along with *)
(* its creation time and date. *)
BEGIN
Volume_Title := Left_Margin_String +
' Contents of volume ' +
Volume_Label +
' as of ' +
DateString +
' ' +
TimeOfDayString;
IF Do_Printer_Format THEN
BEGIN
WRITELN( Output_File , FF_Char );
WRITE ( Output_File , Volume_Title );
WRITELN( Output_File , ' Page ', Page_Number );
END
ELSE
WRITELN( Output_File , Volume_Title );
Volume_Label := Volume_Label + DUPL( ' ' , 12 - LENGTH( Volume_Label ) );
Dir_Convert_Date_And_Time( Vol_Time , SDate , STime );
WRITELN( Output_File );
WRITE ( Output_File , Left_Margin_String,
' Volume: ',Volume_Label );
IF ( SDate <> ' ' ) THEN
WRITE ( Output_File , ' Created: ', SDate, ' ', STime );
DEC( Lines_Left , 3 );
END;
WRITELN( Output_File );
(* Count lines left on page *)
DEC( Lines_Left , 2 );
END (* Display_Volume_Label *);
(*----------------------------------------------------------------------*)
(* Display_Page_Titles --- Display page titles at top of page *)
(*----------------------------------------------------------------------*)
PROCEDURE Display_Page_Titles;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Display_Page_Titles; *)
(* *)
(* Purpose: Displays page headers for paginated output file *)
(* *)
(* Calling sequence: *)
(* *)
(* Display_Page_Titles; *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Display_Page_Titles *)
(* Skip to top of new page using FF *)
WRITELN( Output_File , FF_Char );
(* Reset lines left to page size *)
Lines_Left := Page_Size;
(* Increment page count *)
INC( Page_Number );
(* Display extant titles *)
(* -- Volume title *)
WRITELN( Output_File );
WRITELN( Output_File , Volume_Title , ' Page ', Page_Number );
WRITELN( Output_File );
(* -- Subdirectory title *)
WRITELN( Output_File , Subdir_Title );
WRITELN( Output_File );
DEC( Lines_Left , 5 );
IF ( File_Title <> '' ) THEN
BEGIN
(* -- File title *)
WRITELN( Output_File , File_Title );
WRITELN( Output_File );
DEC( Lines_Left , 2 );
END;
END (* Display_Page_Titles *);
(*----------------------------------------------------------------------*)
(* Include code to process library files. *)
(*----------------------------------------------------------------------*)
(* .ARC display routines *)
(*$I PIBCATA.PAS *)
(* .DWC display routines *)
(*$I PIBCATD.PAS *)
(* .LBR display routines *)
(*$I PIBCATL.PAS *)
(* .MD display routines *)
(*$I PIBCATM.PAS *)
(* .ZOO display routines *)
(*$I PIBCATZ.PAS *)
(*----------------------------------------------------------------------*)
(* Move_File_Info --- Save file information for sorting *)
(*----------------------------------------------------------------------*)
PROCEDURE Move_File_Info( Full : SearchRec;
VAR Short: Short_Dir_Record );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Move_File_Info *)
(* *)
(* Purpose: Saves information about file in compact form *)
(* *)
(* Calling sequence: *)
(* *)
(* Move_File_Info( Full : SearchRec; *)
(* VAR Short: Short_Dir_Record ); *)
(* *)
(* Full --- Directory info as retrieved from DOS *)
(* Short --- Directory info with garbage thrown out *)
(* *)
(* Remarks: *)
(* *)
(* This routine copies the useful stuff about a file to a *)
(* shorter record which is more easily sorted. *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Move_File_Info *)
Short.File_Time := Full.Time;
Short.File_Size := Full.Size;
Short.File_Attr := Full.Attr;
Short.File_Name := Full.Name + DUPL( ' ' , 12 - LENGTH( Full.Name ) );
END (* Move_File_Info *);
(*----------------------------------------------------------------------*)
(* Display_File_Info --- Display information about a file *)
(*----------------------------------------------------------------------*)
PROCEDURE Display_File_Info( Dir_Entry : Short_Dir_Record );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Display_File_Info *)
(* *)
(* Purpose: Displays information for current file *)
(* *)
(* Calling sequence: *)
(* *)
(* Display_File_Info( Dir_Entry : Short_Dir_Record ); *)
(* *)
(* Dir_Entry --- Directory record describing file *)
(* *)
(* Remarks: *)
(* *)
(* The counters for total number of files and total file space *)
(* used are incremented here. *)
(* *)
(*----------------------------------------------------------------------*)
VAR
RLength : LONGINT;
STime : STRING[10];
SDate : STRING[10];
I : INTEGER;
BEGIN (* Display_File_Info *)
WITH Dir_Entry DO
BEGIN
(* Ensure space left this page *)
IF ( Lines_Left < 1 ) THEN
Display_Page_Titles;
(* Get length *)
RLength := File_Size;
(* Get date and time of creation *)
Dir_Convert_Date_And_Time( File_Time , SDate , STime );
(* Write out file name *)
WRITE( Output_File , Left_Margin_String , ' ' , File_Name );
FOR I := LENGTH( File_Name ) TO 14 DO
WRITE( Output_File , ' ');
(* Write length, date, and time *)
WRITE ( Output_File , RLength:8, ' ' );
WRITE ( Output_File , SDate, ' ' );
WRITE ( Output_File , STime );
WRITELN( Output_File );
(* Update count of lines left *)
IF Do_Printer_Format THEN
DEC( Lines_Left );
END;
(* Increment total file count *)
INC( Total_Files );
(* Increment total space used *)
Total_Space := Total_Space + RLength;
END (* Display_File_Info *);
(*----------------------------------------------------------------------*)
(* Sort_Files --- Sort files in ascending order by name *)
(*----------------------------------------------------------------------*)
PROCEDURE Sort_Files( First : INTEGER;
Last : INTEGER );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Sort_Files *)
(* *)
(* Purpose: Sorts file names in current directory *)
(* *)
(* Calling sequence: *)
(* *)
(* Sort_Files( First : INTEGER; Last : INTEGER ); *)
(* *)
(* First --- First entry in 'File_Stack' to sort *)
(* Last --- Last entry in 'File_Stack' to sort *)
(* *)
(* Remarks: *)
(* *)
(* A shell sort is used to put the file names for the current *)
(* directory in ascending order. The current directory's files *)
(* are bracketed by 'First' and 'Last'. *)
(* *)
(*----------------------------------------------------------------------*)
VAR
Temp : Short_Dir_Record;
I : INTEGER;
J : INTEGER;
D : INTEGER;
BEGIN (* Sort_Files *)
D := SUCC( Last - First );
WHILE( D > 1 ) DO
BEGIN
IF ( D < 5 ) THEN
D := 1
ELSE
D := TRUNC( 0.45454 * D );
FOR I := ( Last - D ) DOWNTO First DO
BEGIN
Temp := File_Stack[ I SHR SegShift ]^[ I AND MaxFiles ];
J := I + D;
WHILE( ( Temp.File_Name >
File_Stack[ J SHR SegShift ]^[ J AND MaxFiles ].File_Name ) AND
( J <= Last ) ) DO
BEGIN
File_Stack[ ( J - D ) SHR SegShift ]^[ ( J - D ) AND MaxFiles ] :=
File_Stack[ J SHR SegShift ]^[ J AND MaxFiles ];
J := J + D;
END;
File_Stack[ ( J - D ) SHR SegShift ]^[ ( J - D ) AND MaxFiles ] := Temp;
END;
END;
END (* Sort_Files *);
(*----------------------------------------------------------------------*)
(* Find_Files --- Recursively search directories for files *)
(*----------------------------------------------------------------------*)
PROCEDURE Find_Files( VAR Subdir : AnyStr;
VAR File_Spec : AnyStr;
Attr : INTEGER;
Levels : INTEGER );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Find_Files *)
(* *)
(* Purpose: Recursively traverses directories looking for files *)
(* *)
(* Calling sequence: *)
(* *)
(* Find_Files( VAR Subdir : AnyStr; *)
(* VAR File_Spec : AnyStr; *)
(* Attr : INTEGER; *)
(* Levels : INTEGER ); *)
(* *)
(* Subdir --- subdirectory name of this level *)
(* File_Spec --- DOS file spec to match *)
(* Attr --- attribute type to match *)
(* Levels --- current subdirectory level depth *)
(* *)
(* Remarks: *)
(* *)
(* This is the actual heart of PibCat. This routine invokes *)
(* itself recursively to traverse all subdirectories looking for *)
(* files which match the given file specification. *)
(* *)
(*----------------------------------------------------------------------*)
VAR
Dir_Entry : SearchRec;
Path : AnyStr;
Error : INTEGER;
I : INTEGER;
Dir : STRING[14];
Cur_Count : INTEGER;
Skip_Attr : INTEGER;
Files_Here : INTEGER;
ISeg : INTEGER;
IOff : INTEGER;
LABEL Quit;
BEGIN (* Find_Files *)
(* Save current file count *)
Cur_Count := File_Count;
(* No files in this directory yet *)
Files_Here := 0;
(* Don't list directories as files *)
Skip_Attr := VolumeID + Directory;
IF ( Levels >= 1 ) THEN
BEGIN
(* Get full file spec to search for *)
Path := Subdir + File_Spec;
(* Get first file on this level *)
FindFirst( Path, AnyFile, Dir_Entry );
Error := DosError;
(* Get info on remaining files *)
(* on this level. *)
WHILE ( Error = 0 ) DO
BEGIN
(* Increment count of files in this dir *)
(* including subdirectories *)
INC( File_Count );
(* Increment non-directory file count *)
IF ( ( Dir_Entry.Attr AND Skip_Attr ) = 0 ) THEN
INC( Files_Here );
(* Save info on this file *)
Move_File_Info ( Dir_Entry ,
File_Stack[ File_Count SHR SegShift ]^[ File_Count AND MaxFiles ] );
(* Get next file entry *)
FindNext( Dir_Entry );
Error := DosError;
(* Check for ^C at keyboard *)
IF KeyPressed THEN
IF QuitFound THEN
GOTO Quit;
END;
(* Sort file names *)
Sort_Files( SUCC( Cur_Count ) , File_Count );
(* Increment directory count *)
INC ( Total_Dirs );
(* Report scanning this subdirectory *)
WRITELN(' Scanning: ', Subdir );
(* Display file info header *)
IF ( Files_Here > 0 ) THEN
BEGIN
Subdir_Title := Left_Margin_String + ' Directory: ' + Subdir;
IF Do_Printer_Format THEN
IF ( Lines_Left < 4 ) THEN
Display_Page_Titles
ELSE
BEGIN
WRITELN( Output_File );
WRITELN( Output_File , Subdir_Title );
WRITELN( Output_File );
END
ELSE
BEGIN
WRITELN( Output_File );
WRITELN( Output_File , Subdir_Title );
WRITELN( Output_File );
END;
(* Count lines left on page *)
IF Do_Printer_Format THEN
BEGIN
DEC( Lines_Left , 3 );
IF ( Lines_Left < 1 ) THEN
Display_Page_Titles;
END;
END;
(* Display info on all files *)
(* But don't display directories! *)
FOR I := SUCC( Cur_Count ) TO File_Count DO
BEGIN
ISeg := I SHR SegShift;
IOff := I AND MaxFiles;
IF ( ( File_Stack[ ISeg ]^[ IOff ].File_Attr AND Skip_Attr ) = 0 ) THEN
Display_File_Info( File_Stack[ ISeg ]^[ IOff ] );
IF ( Expand_Libs AND Expand_Libs_In ) THEN
BEGIN
IF ( POS( '.ARC', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_Archive_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.PAK', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_Archive_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.DWC', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_DWC_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.LBR', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_Lbr_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.MD ', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_MD_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.ZOO', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_ZOO_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name );
END;
IF KeyPressed THEN
IF QuitFound THEN
GOTO Quit;
END;
(* List library file contents if requested *)
IF ( Expand_Libs AND ( NOT Expand_Libs_In ) ) THEN
BEGIN
(* List contents of any .ARC files *)
FOR I := SUCC( Cur_Count ) TO File_Count DO
BEGIN
ISeg := I SHR SegShift;
IOff := I AND MaxFiles;
(* If current file is any type of *)
(* library file, then list contents *)
IF ( POS( '.ARC', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_Archive_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.PAK', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_Archive_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.DWC', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_DWC_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.LBR', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_Lbr_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.MD ', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_MD_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name )
ELSE IF ( POS( '.ZOO', File_Stack[ ISeg ]^[ IOff ].File_Name ) > 0 ) THEN
Display_ZOO_Contents( Subdir + File_Stack[ ISeg ]^[ IOff ].File_Name );
(* If <CTRL>Break hit, quit. *)
IF KeyPressed THEN
IF QuitFound THEN
GOTO Quit;
END;
END;
IF ( Levels >= 2 ) THEN
BEGIN
(* List all subdirectories to given level *)
(* Note: we read through whole directory *)
(* again since we probably excluded *)
(* directories on first pass. *)
Path := Subdir + '*.*';
(* Get first file *)
FindFirst( Path, AnyFile, Dir_Entry );
Error := DosError;
(* While there are files left ... *)
WHILE ( Error = 0 ) DO
BEGIN
(* See if it's a subdirectory *)
IF ( ( Dir_Entry.Attr AND Directory ) <> 0 ) THEN
BEGIN
(* Yes -- get subdirectory name *)
Dir := Dir_Entry.Name;
(* Ignore '.' and '..' *)
IF ( ( Dir <> '.' ) AND ( Dir <> '..') ) THEN
BEGIN
(* Construct path name for subdirectory *)
Path := Subdir + Dir + '\';
(* List files in subdirectory *)
Find_Files( Path, File_Spec, Attr, PRED( Levels ) );
IF User_Break THEN
GOTO Quit;
END;
END;
(* Get next file entry *)
FindNext( Dir_Entry );
Error := DosError;
END (* WHILE *);
END (* IF Levels >= 2 *);
END (* IF Levels >= 1 *);
(* Restore previous file count *)
Quit:
File_Count := Cur_Count;
END (* Find_Files *);
(*----------------------------------------------------------------------*)
(* Perform_Cataloguing --- Do cataloguing of files *)
(*----------------------------------------------------------------------*)
PROCEDURE Perform_Cataloguing;
VAR
Name : AnyStr;
Subdir : AnyStr;
File_Spec : AnyStr;
I : INTEGER;
L : INTEGER;
Done : BOOLEAN;
BEGIN (* Perform_Cataloguing *)
(* Display volume label *)
Display_Volume_Label;
(* Append disk letter to file spec *)
IF ( POS( '\' , Find_Spec ) = 0 ) THEN
Name := Cat_Drive + ':\' + Find_Spec
ELSE
Name := Cat_Drive + ':' + Find_Spec;
(* Make sure some files get looked at! *)
IF Name[LENGTH(Name)] = '\' THEN
Name := Name + '*.*';
(* Split out directory from file spec *)
Subdir := Name;
I := SUCC( LENGTH( Subdir ) );
Done := FALSE;
REPEAT
DEC( I );
IF ( I > 0 ) THEN
Done := ( Subdir[I] = '\' )
ELSE
Done := TRUE;
UNTIL Done;
I := LENGTH( Subdir ) - I;
File_Spec[0] := CHR( I );
MOVE( Subdir[ 1 + LENGTH( Subdir ) - I ] , File_Spec[ 1 ] , I );
Subdir[0] := CHR( LENGTH( Subdir ) - I );
(* Begin listing files at specified *)
(* subdirectory *)
Find_Files( Subdir, File_Spec, $FF, 9999 );
END (* Perform_Cataloguing *);
(*----------------------------------------------------------------------*)
(* Terminate --- Terminate cataloguing *)
(*----------------------------------------------------------------------*)
PROCEDURE Terminate;
VAR
I : INTEGER;
BEGIN (* Terminate *)
(* Note if catalogue terminated by ^C *)
IF ( NOT Help_Only ) THEN
IF User_Break THEN
BEGIN
IF ( Lines_Left < 6 ) THEN
Display_Page_Titles;
WRITELN( Output_File );
WRITELN( Output_File , Left_Margin_String,
'>>>>> ^C typed, catalog listing INCOMPLETE.');
WRITELN( Output_File );
WRITELN( '^C typed, catalog listing INCOMPLETE.');
END
ELSE
BEGIN (* Indicate file totals *)
IF ( Lines_Left < 9 ) THEN
Display_Page_Titles;
WRITELN( Output_File );
WRITELN( Output_File , Left_Margin_String, ' Totals:');
WRITELN( Output_File , Left_Margin_String,
' Directories scanned: ',Total_Dirs:10);
WRITELN( Output_File , Left_Margin_String,
' Files selected : ',Total_Files:10);
WRITELN( Output_File , Left_Margin_String,
' Bytes in files : ',Total_Space:10);
WRITELN( Output_File , Left_Margin_String,
' Entries selected : ',Total_Entries:10);
WRITELN( Output_File , Left_Margin_String,
' Bytes in entries : ',Total_ESpace:10);
WRITELN( Output_File , Left_Margin_String,
' Bytes free : ',
DiskFree( SUCC( ORD( Cat_Drive ) - ORD('A') ) ):10 );
END;
(* Close output file *)
(*$I-*)
CLOSE( Output_File );
(*$I+*)
IF ( IOResult <> 0 ) THEN;
END (* Terminate *);
(*---------------------- Main Program of PIBCAT ------------------------*)
BEGIN (* PibCat *)
(* Initialize program. If initialization *)
(* goes OK, then perform cataloguing. *)
IF Initialize THEN
Perform_Cataloguing;
(* Close output file and terminate. *)
Terminate;
END (* PibCat *).